/**
 * File SpeechBubblePopup.java
 * ---------------------------------------------------------
 *
 * Copyright (C) 2012 David Bauske (david.bauske@googlemail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * - The origin of the software must not be misrepresented.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * TL;DR: As long as you clearly give me credit for this Software, you are free to use as you like, even in commercial software, but don't blame me
 * 		if it breaks something.
 */
package net.cl.util.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.GeneralPath;
import java.awt.geom.RoundRectangle2D;

import javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.JWindow;
import javax.swing.Popup;
import javax.swing.SwingUtilities;

import com.sun.awt.AWTUtilities;

/**
 * Popup window class that creates a speech-bubble-shaped popup window.
 *
 * @author David
 */
public class SpeechBubblePopup extends Popup
{
	private final SpeechBubbleWindow	popupWindow;

	// Size of the arrow from the tooltip to it's component in pixels.
	private static final int			POINTER_HEIGHT		= 10;
	private static final int			POINTER_X_OFFSET	= 10;
	private static final int			POINTER_WIDTH		= 20;

	private static final int			BUBBLE_Y_OFFSET		= -3;

	private static final int CORNER_RADIUS = 10;
	private static final int TEXT_BORDER = 8;
	private static final int BORDER_WIDTH = 1;

	private static class SpeechBubbleWindow extends JWindow
	{
		private static final long	serialVersionUID	= -6582834396354134627L;

		private static final Color 	BACKGROUND_COLOR 	= new Color(255, 255, 150);
		private static final Color 	BACKGROUND_BORDER 	= Color.GRAY;

		private final SpeechBubblePanel	mPanel;
		private final String			mText;
		private boolean					mTransparencySupported	= true;

		public SpeechBubbleWindow(JToolTip pToolTip, String pText)
		{
			this.mText = pText;

			mPanel = new SpeechBubblePanel();
			this.add(mPanel);
		}

		private class SpeechBubblePanel extends JPanel
		{
			private static final long serialVersionUID = -3070603923324450813L;

			@Override
			protected void paintComponent(Graphics g)
			{
				Graphics2D g2d = (Graphics2D) g;

				g2d.setColor(BACKGROUND_COLOR);

				int backgroundHeight = getHeight() - POINTER_HEIGHT;

				// Draw background rectangle
				RoundRectangle2D bg = null;
				if(mTransparencySupported)
				{
					bg = new RoundRectangle2D.Double(0, POINTER_HEIGHT, getWidth()
							- BORDER_WIDTH,
							backgroundHeight - BORDER_WIDTH, CORNER_RADIUS, CORNER_RADIUS);

				}

				g2d.fill(bg);
				g2d.setColor(BACKGROUND_BORDER);
				g2d.draw(bg);

				// Draw the text on the tooltip
				g2d.setColor(Color.BLACK);
				g2d.drawString(mText, TEXT_BORDER, (int) (POINTER_HEIGHT + backgroundHeight * (2.0/3.0)));

				// Draw the arrow
				GeneralPath triangle = new GeneralPath();
				triangle.moveTo(POINTER_X_OFFSET, POINTER_HEIGHT);
				triangle.lineTo(POINTER_X_OFFSET + POINTER_WIDTH / 2, 0);
				triangle.lineTo(POINTER_X_OFFSET + POINTER_WIDTH, POINTER_HEIGHT);
				triangle.closePath();
				g2d.setColor(BACKGROUND_COLOR);
				g2d.fill(triangle);
				g2d.setColor(BACKGROUND_BORDER);
				g2d.draw(triangle);

				// Remove the border line
				g2d.setColor(BACKGROUND_COLOR);
				g2d.drawLine(POINTER_X_OFFSET + 1, POINTER_HEIGHT, POINTER_X_OFFSET + POINTER_WIDTH - 1, POINTER_HEIGHT);
			}
		}
	}

	SpeechBubblePopup(Component owner, Component contents, int ownerX, int ownerY)
	{
		// create a new heavyweight window
		JToolTip toolTip = (JToolTip) contents;
		Dimension ttSize = toolTip.getPreferredSize();

		this.popupWindow = new SpeechBubbleWindow(toolTip, toolTip.getTipText());
		this.popupWindow.setAlwaysOnTop(true);

		// determine the popup location
		Point absPos = new Point(0, 0);
		SwingUtilities.convertPointToScreen(absPos, owner);
		popupWindow.setLocation(absPos.x, absPos.y + owner.getHeight() + BUBBLE_Y_OFFSET);

		popupWindow.setSize(new Dimension(ttSize.width + TEXT_BORDER, ttSize.height + POINTER_HEIGHT));

	}

	@Override
	public void show()
	{
		this.popupWindow.setVisible(true);

		try
		{
			AWTUtilities.setWindowOpaque(this.popupWindow, false);
		}
		catch(Exception e)
		{
			// Catching all exceptions here since it varies from JVM to JVM which exception gets thrown
			// if the operation fails.
			this.popupWindow.mTransparencySupported = false;
		}
	}

	@Override
	public void hide()
	{
		this.popupWindow.setVisible(false);
		this.popupWindow.removeAll();
		this.popupWindow.dispose();
	}
}
